#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
/**
 * @Auther: lizhx
 * @Date: ${DATE} ${HOUR}:${MINUTE}
 * @Description: 
 */
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import javax.inject.Inject;
import javax.inject.Named;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

@Component
public interface ${NAME} {
	/**
	 * 获取redis锁
	 * @param lockHolder 持锁线程
	 * @param lockKey 锁
	 * @param keyExpire 锁的有效期
	 * @return
	 * @throws Exception
	 */
	public boolean tryLock(String lockHolder,String lockKey,long keyExpire) throws Exception;

	/**
	 * 获取redis锁(使用默认过期时间)
	 * @param lockHolder 持锁线程
	 * @param lockKey 锁
	 * @return
	 * @throws Exception
	 */
	public boolean tryLock(String lockHolder,String lockKey) throws Exception;

	/**
	 * 获取锁，noWait
	 * @param lockHolder
	 * @param lockKey
	 * @param keyExpire
	 * @return
	 * @throws Exception
	 */
	public boolean lock(String lockHolder,String lockKey,long keyExpire) throws Exception;

	/**
	 * 解锁
	 * @param lockHolder
	 * @param lockKey
	 * @return
	 */
	public boolean unLock(String lockHolder,String lockKey) ;
	@Component
	class Impl implements ${NAME} {
		private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(${NAME}.class);
		@Inject
		//@Named(RedisName.VIDEO)//TODO 
		private RedisTemplate redis;
		private long maxWaitMillis=5000l;//最大等待2s
		private long perWaitMillis=100l;//延迟等待100ms
		private final long KEY_EXPIRE = 3000l;//默认过期时间3s

		/**
		 *
		 * @param lockHolder
		 * @param lockKey
		 * @param keyExpire
		 * @return
		 * @throws Exception
		 */
		@Override
		public boolean lock(String lockHolder,String lockKey,long keyExpire) throws Exception {
			return (boolean)redis.execute(new SessionCallback() {
				@Override
				public Object execute(RedisOperations operations) throws DataAccessException {
					boolean isLocked = operations.opsForValue().setIfAbsent(lockKey,lockHolder);
					if(isLocked){
						isLocked = operations.expire(lockKey,keyExpire,TimeUnit.MILLISECONDS);
					}
					return isLocked;
				}
			});
		}
		/**
		 *
		 * @param lockHolder
		 * @param lockKey
		 * @return
		 * @throws Exception
		 */
		@Override
		public boolean unLock(String lockHolder,String lockKey) {
			if (lockHolder.equals( redis.opsForValue().get(lockKey)==null ? "":(String)redis.opsForValue().get(lockKey))) {
				redis.delete(lockKey);
				return true;
			}else{
				return false;
			}
		}

		@Override
		public boolean tryLock(String lockHolder,String lockKey,long keyExpire) throws Exception {
			long waitAlready=0l;
			boolean isLock = false;
			//1.在最大时间内获取到了lock即有效时间内获取到锁返回成功
			try {
				while (isLock!=true && waitAlready <= maxWaitMillis) {
					isLock = lock(lockHolder,lockKey,keyExpire);
					if(isLock==false){
						Thread.sleep(perWaitMillis);
						waitAlready += perWaitMillis;
					}
				}
			}catch (Exception e){
				LOGGER.error("获取锁异常",e);
				isLock = false;//异常否则返回失败
			}
			//2.在最大时间内未获取到了lock或超过最大等待时间返回失败
			return isLock;
		}
		@Override
		public boolean tryLock(String lockHolder,String lockKey) throws Exception {
			return tryLock(lockHolder,lockKey,KEY_EXPIRE);
		}
	}
}
    